Network Analysis, based in graph theory, provides a means to easily interpret and analyze the linked connections between individual movements and receivers (Griffen et al., 2018). Network analysis in general is being applied to biotelemetry by looking at the relations within animal movements as a social network (Finn et al., 2014).
Pull in the necessary libraries:
library(tidyverse)
library(glatos)
library(plotly)
We are going to load the sample walleye fish detections from the Great Lakes, filter them, and then compress them.
detections_path <- file.path('..', 'data', 'detections.csv')
detections <- read_glatos_detections(detections_path)
detections <- glatos::false_detections(detections, tf = 3600)
## The filter identified 93 (1.3%) of 7180 detections as potentially false.
filtered_detections <- detections %>% filter(passed_filter != FALSE)
detection_events <- glatos::detection_events(filtered_detections, location_col = 'station')
## The event filter distilled 7087 detections down to 3537 distinct detection events.
Below we create 2 data frames. One to create the network edges and the other to create the vertices.
# create a data frame of directed movements
network_analysis_data <-
detection_events %>%
arrange(first_detection) %>% # Arrange in sequential order by time of arrival
group_by(animal_id) %>% # Group the data animal
mutate(to = lead(location), # Create a next location column by using the lead
to_latitude = lead(mean_latitude), # Create a next latitude column by using the lead
to_longitude = lead(mean_longitude)) %>% # Create a next longitude column by using the lead
group_by(location, to) %>% # Group by unique sets of movements/vertices
summarise(visits = n(),
latitude = mean(mean_latitude),
longitude=mean(mean_longitude),
to_latitude=mean(to_latitude),
to_longitude=mean(to_longitude),
res_time_seconds = mean(res_time_sec) # Summarise the data into data frame of moves by counting them and averaging the the rest of the values
) %>%
rename(from=location) %>% # Rename the originating station to 'from'
na.omit() # Omit any rows with empty values
# Create a data frame of receiver vertices.
receivers <-
network_analysis_data %>%
group_by(from) %>%
summarise(
latitude = mean(latitude),
longitude = mean(longitude),
visits = sum(visits),
res_time_seconds = mean(res_time_seconds)
)
Below we plot out the segments and vertices using plotly.
network <-
network_analysis_data %>%
plot_mapbox(height=800) %>%
add_segments(
x = ~longitude, xend = ~to_longitude,
y = ~latitude, yend = ~to_latitude,
size = I(1.5), hoverinfo = "none", color=I(toRGB("#AA3939"))
) %>%
add_markers(
data=receivers,
x = ~longitude, y = ~latitude, text = ~paste(from, ":", visits, ' visits & ', res_time_seconds, ' seconds of residence time on average'),
size = ~res_time_seconds/mean(network_analysis_data$res_time_seconds) + 100, hoverinfo = "text", color=~visits
) %>%
layout(
title = 'Walleye Salmon Network Plot',
showlegend = FALSE,
mapbox = list(zoom = 6,
center = list(lat = ~median(latitude),
lon = ~median(longitude)),
style='light'
)
)
network
## Warning: `line.width` does not currently support multiple values.
Lets recreate this using the mapview package. Here we will use a package called leaflet.minicharts that help plot the directionality and weights in edges of the network.
library(mapview)
library(leaflet.minicharts)
library(sf)
## Linking to GEOS 3.7.2, GDAL 2.4.2, PROJ 5.2.0
# First lets create a basemap with all the residence times at each receivers mapped
basemap <-
receivers %>%
st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>%
mapview(color.regions = "white",
cex = "visits",
alpha = 0,
homebutton = F,
legend = F)
m <-
basemap@map %>%
addFlows(lng0 = network_analysis_data$longitude,
lat0 = network_analysis_data$latitude,
lng1 = network_analysis_data$to_longitude,
lat1 = network_analysis_data$to_latitude,
flow = network_analysis_data$visits,
color = "black",
opacity = 0.8)
m